﻿//
//  Manyou.Toolkit.Util.cs:
//  Authors:
//	Bryan Chow (cabir.zhou@gmail.com)
//
//
//  No Trademark License- This license does not grant you rights to use any 
//  contributors' name, logo, or trademarks.
//
//  If you bring a patent claim against any contributor over patents that you
//  claim are infringed by the software, your patent license from such 
//  contributor to the software ends automatically.
//
//  If you distribute any portion of the software, you must retain
//  all copyright, patent, trademark, and attribution notices that are present in the software.
//
//  If you distribute any portion of the software in source code form,
//  you may do so only under this license by including a complete copy of this license
//  with your distribution. If you distribute any portion of the software
//  in compiled or object code form, you may only do so under a license that complies with this license.
//
//  The software is licensed "as-is." You bear the risk of using it. 
//  The contributors give no express warranties, guarantees or conditions.
//  You may have additional consumer rights under your local laws which 
//  this license cannot change. To the extent permitted under your local laws,
//  the contributors exclude the implied warranties of merchantability,
//  fitness for a particular purpose and non-infringement.
//

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Newtonsoft.Json; 

namespace Manyou.Toolkit
{
    public class Util
    {
        private const string LINE = "\r\n";

        private string api_key;
        private string secret;
        private string url;
        private bool use_json;

        public Util(string api_key, string secret, string url)
        {
            this.api_key = api_key;
            this.secret = secret;
            this.url = url;
        }
        public Dictionary<string, string> Parms = new Dictionary<string, string>();

        public bool UseJson
        {
            get { return use_json; }
            set { use_json = value; }
        }

        internal string SharedSecret
        {
            get { return secret; }
            set { secret = value; }
        }

        internal string ApiKey
        {
            get { return api_key; }
        }

        internal string Url
        {
            get { return url; }
            set { url = value; }
        }

        /// <summary>
        /// 将Unicode字串\u....\u....格式字串转换为原始字符串
        /// </summary>
        /// <param name="srcText"></param>
        /// <returns></returns>
        private string UnicodeToString(string srcText)
        {
            string text = srcText;
            string strPattern = "(?<code>\\\\u[A-F0-9]{4})";
            do
            {
                Match m = Regex.Match(text, strPattern, RegexOptions.IgnoreCase);
                if (m.Success)
                {
                    string strValue = m.Groups["code"].Value;
                    int i = System.Int32.Parse(strValue.Substring(2, 4), System.Globalization.NumberStyles.HexNumber);
                    char ch = Convert.ToChar(i);
                    text = text.Replace(strValue, ch.ToString());
                }
                else
                {
                    break;
                }
            }
            while (true);

            return text;
        }

        /// <summary>
        /// 读cookie值
        /// </summary>
        /// <param name="strName">名称</param>
        /// <returns>cookie值</returns>
        public string GetCookie(string strName)
        {
            if (HttpContext.Current.Request.Cookies != null && HttpContext.Current.Request.Cookies[strName] != null)
            {
                return HttpContext.Current.Request.Cookies[strName].Value.ToString();
            }

            return string.Empty;
        }


        public T GetJsonResponse<T>(string method_name, params ManyouParam[] parameters)
        {
            ManyouParam[] signed = Sign(method_name, parameters);

            StringBuilder builder = new StringBuilder();

            for (int i = 0; i < signed.Length; i++)
            {
                if (i > 0)
                    builder.Append("&");

                builder.Append(string.Format("{0}={1}", signed[i].Name, signed[i].EncodedValue));//signed[i].ToString());
            }


            string responseStr = GetResponseBytes(/*"http://api.manyou.com/openapi.php"*/this.url, method_name, builder.ToString());
            responseStr = UnicodeToString(responseStr);
            responseStr = responseStr.Replace("\\/", "/");
            //responseStr = responseStr.Replace(":null", ":\"\"");

            try
            {
                T response = JsonConvert.DeserializeObject<T>(responseStr); 
                if ((response as ResponseBase).ErrorCode > 0)
                {
                    throw new ManyouException((response as ResponseBase).ErrorCode, (response as ResponseBase).ErrorMsg);
                }
                return response;
            }
            catch
            {
                Error error = (Error)JsonConvert.DeserializeObject(responseStr, typeof(Error));
                throw new ManyouException(error.ErrorCode, error.ErrorMsg);
            }
        }

        public static byte[] GetResponseBytes(string url)
        {
            WebRequest request = HttpWebRequest.Create(url);
            WebResponse response = null;

            try
            {
                response = request.GetResponse();
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return Encoding.UTF8.GetBytes(reader.ReadToEnd());
                }
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
        }

        public static string GetResponseBytes(string apiUrl, string method_name, string postData)
        {


            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(apiUrl);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = postData.Length;
            request.Timeout = 20000;

            HttpWebResponse response = null;

            try
            {
                StreamWriter swRequestWriter = new StreamWriter(request.GetRequestStream());
                swRequestWriter.Write(postData);
                if (swRequestWriter != null)
                    swRequestWriter.Close();

                response = (HttpWebResponse)request.GetResponse();
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
        }

        private string FormatGetUrl(string method_name, params ManyouParam[] parameters)
        {
            ManyouParam[] signed = Sign(method_name, parameters);

            StringBuilder builder = new StringBuilder(Url);

            for (int i = 0; i < signed.Length; i++)
            {
                if (i > 0)
                    builder.Append("&");

                builder.Append(signed[i].ToString());
            }

            return builder.ToString();
        }
        
        public string GenerateSig(Dictionary<string, string> parameters, string prefix)
        {
            List<string> list = new List<string>(parameters.Keys);
            StringComparer ordCmp = StringComparer.Ordinal;
            list.Sort(ordCmp);


            StringBuilder values = new StringBuilder();

            foreach (string key in list)
            {
                if (string.IsNullOrEmpty(parameters[key]) || parameters[key] == "0")
                    continue;
                values.Append(string.Format("{0}{1}={2}", prefix, key, parameters[key]));
                values.Append("&");
            }
            values.Append(secret);

            byte[] md5_result = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(values.ToString()));

            StringBuilder sig_builder = new StringBuilder();

            foreach (byte b in md5_result)
                sig_builder.Append(b.ToString("x2"));

            return sig_builder.ToString();
        }

        public void SetCookies(Dictionary<string, string> parameters, int expires)
        {
            //tell stupid ie browser to write cross-domain cookie
            HttpContext.Current.Response.AddHeader("p3p", "CP=IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT");

            Dictionary<string, string> list = new Dictionary<string,string>();


            AddCookie(this.api_key + "_" + "uId", parameters["uId"], expires);
            list.Add(this.api_key + "_" + "uId", parameters["uId"]);


            AddCookie(this.api_key + "_" + "sId", parameters["sId"], expires);
            list.Add(this.api_key + "_" + "sId", parameters["sId"]);

            AddCookie(this.api_key + "_" + "sessionId", parameters["sessionId"], expires);
            list.Add(this.api_key + "_" + "sessionId", parameters["sessionId"]);

            AddCookie(this.api_key + "_" + "prefix", parameters["prefix"], expires);
            AddCookie(this.api_key + "_" + "appId", parameters["appId"], expires);
            AddCookie(this.api_key + "_" + "added", parameters["added"], expires);
            AddCookie(this.api_key + "_" + "key", GenerateSig(list, ""), expires);
           
        }

        private HttpCookie AddCookie(string name, string value, int expires)
        {
            HttpCookie cookie = new HttpCookie(name, value);
            cookie.Expires = DateTime.Now.AddSeconds(expires);
            HttpContext.Current.Response.AppendCookie(cookie);
            return cookie;
        }

        internal ManyouParam[] Sign(string method_name, ManyouParam[] parameters)
        {
            List<ManyouParam> list = new List<ManyouParam>();
            list.Add(ManyouParam.Create("method", method_name));
            list.Add(ManyouParam.Create("api_key", api_key));
            //list.Add(ManyouParam.Create("call_id", System.Environment.TickCount));
            list.Add(ManyouParam.Create("v", "0.1"));
            list.Add(ManyouParam.Create("format", "JSON"));
            list.Add(ManyouParam.Create("session_key", Parms["sessionId"]));
            list.Sort();

            StringBuilder values = new StringBuilder();

            foreach (ManyouParam param in list)
            {
                values.Append(param.ToString());
                values.Append("&");
            }



            List<ManyouParam> list1 = new List<ManyouParam>(parameters);
            list1.Sort();

            foreach (ManyouParam param in list1)
            {
                param.Name = string.Format("args[{0}]", param.Name);
                values.Append(param.ToString());
                values.Append("&");
                list.Add(param);
            }



            values.Append(secret);

            byte[] md5_result = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(values.ToString()));

            StringBuilder sig_builder = new StringBuilder();

            foreach (byte b in md5_result)
                sig_builder.Append(b.ToString("x2"));

            list.Add(ManyouParam.Create("sig", sig_builder.ToString()));

            return list.ToArray();
        }

        internal static int GetIntFromString(string input)
        {
            try
            {
                return int.Parse(input);
            }
            catch
            {
                return 0;
            }
        }

        internal static bool GetBoolFromString(string input)
        {
            try
            {
                return bool.Parse(input);
            }
            catch
            {
                return false;
            }

        }

        /// <summary>
        /// 判断指定字符串在指定字符串数组中的位置
        /// </summary>
        /// <param name="strSearch">字符串</param>
        /// <param name="stringArray">字符串数组</param>
        /// <param name="caseInsensetive">是否不区分大小写, true为不区分, false为区分</param>
        /// <returns>字符串在指定字符串数组中的位置, 如不存在则返回-1</returns>
        internal static int GetInArrayID(string strSearch, string[] stringArray, bool caseInsensetive)
        {
            for (int i = 0; i < stringArray.Length; i++)
            {
                if (caseInsensetive)
                {
                    if (strSearch.ToLower() == stringArray[i].ToLower())
                    {
                        return i;
                    }
                }
                else
                {
                    if (strSearch == stringArray[i])
                    {
                        return i;
                    }
                }

            }
            return -1;
        }

        /// <summary>
        /// 判断指定字符串是否属于指定字符串数组中的一个元素
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="stringarray">内部以逗号分割单词的字符串</param>
        /// <returns>判断结果</returns>
        public static bool InArray(string str, string stringarray)
        {
            return GetInArrayID(str, stringarray.Split(','), false) >= 0;
        }



    }
}
